// Package client 提供与外部服务的客户端实现
// 主要包含豆包API客户端，支持图片内容分析功能
package client

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"

	"ubbc/internal/config"
	"ubbc/internal/interfaces"
	"ubbc/internal/model"
	"ubbc/pkg/logger"
)

// DoubaoClient 豆包API客户端结构体
// 提供调用豆包API进行图片内容分析的功能
type DoubaoClient struct {
	config     *config.DoubaoConfig // 豆包配置
	httpClient *http.Client         // HTTP客户端
	logger     *logger.Logger       // 日志记录器
	rules      []config.Rule        // 规则集合
}

// NewDoubaoClient 创建新的豆包客户端
// 配置HTTP客户端的超时时间和重试策略
func NewDoubaoClient(cfg *config.DoubaoConfig, log *logger.Logger, rules []config.Rule) *DoubaoClient {
	return &DoubaoClient{
		config: cfg,
		httpClient: &http.Client{
			Timeout: cfg.Timeout.ToDuration(),
		},
		logger: log,
		rules:  rules,
	}
}

// AnalyzeImage 分析图片内容 - 豆包版本
// 使用单次AI调用完成所有规则检查，提升性能和并发处理能力
// 返回json字符串，包含overallResult、命中rules-name集合、详细判定
func (c *DoubaoClient) AnalyzeImage(ctx context.Context, imageURL, requestID string) (string, error) {
	reqLogger := c.logger.WithRequestID(requestID)

	// 验证图片URL的有效性
	if err := c.validateImageURL(imageURL); err != nil {
		reqLogger.Error("Invalid image URL", map[string]interface{}{
			"image_url": imageURL,
			"error":     err.Error(),
		})
		return "", fmt.Errorf("invalid image URL: %w", err)
	}

	// 构建智能化的单次分析prompt
	prompt := c.buildComprehensivePrompt(imageURL)
	
	// 构建豆包API请求
	doubaoReq := c.buildDoubaoRequest(imageURL, prompt)

	// 单次AI调用完成所有分析
	aiResponse, err := c.sendRequest(ctx, doubaoReq, requestID)
	if err != nil {
		reqLogger.Warn("Doubao analysis failed, using fallback", map[string]interface{}{"error": err.Error()})
		return c.fallbackAnalysis(ctx, imageURL, requestID)
	}

	// 尝试解析AI返回的结构化结果
	result, err := c.parseAIResponse(aiResponse, reqLogger)
	if err != nil {
		reqLogger.Warn("Failed to parse Doubao response, using fallback", map[string]interface{}{"error": err.Error(), "response": aiResponse})
		return c.fallbackAnalysis(ctx, imageURL, requestID)
	}

	resultJson, err := json.Marshal(result)
	if err != nil {
		return "", fmt.Errorf("failed to marshal result: %w", err)
	}

	reqLogger.Debug("Doubao analysis completed", map[string]interface{}{
		"violated": result["violated"],
		"rules_count": len(c.rules),
	})

	return string(resultJson), nil
}

// validateImageURL 验证图片URL的有效性
// 检查URL格式和域名是否在允许列表中
func (c *DoubaoClient) validateImageURL(imageURL string) error {
	// 解析URL
	parsedURL, err := url.Parse(imageURL)
	if err != nil {
		return fmt.Errorf("invalid URL format: %w", err)
	}

	// 检查协议
	if parsedURL.Scheme != "http" && parsedURL.Scheme != "https" {
		return fmt.Errorf("unsupported URL scheme: %s", parsedURL.Scheme)
	}

	// 检查主机名
	if parsedURL.Host == "" {
		return fmt.Errorf("missing host in URL")
	}

	return nil
}

// buildDoubaoRequest 构建豆包API请求
// 根据图片URL和prompt构造符合豆包API格式的请求体
func (c *DoubaoClient) buildDoubaoRequest(imageURL, prompt string) *model.DoubaoRequest {
	return &model.DoubaoRequest{
		Model: c.config.Model,
		Messages: []model.DoubaoMessage{
			{
				Role: "user",
				Content: []model.DoubaoMessageContent{
					{
						Type: "text",
						Text: prompt,
					},
					{
						Type: "image_url",
						ImageURL: &model.DoubaoImageURL{
							URL: imageURL,
						},
					},
				},
			},
		},
	}
}

// sendRequest 发送HTTP请求到豆包API
// 处理请求序列化、HTTP调用和响应解析
func (c *DoubaoClient) sendRequest(ctx context.Context, doubaoReq *model.DoubaoRequest, requestID string) (string, error) {
	reqLogger := c.logger.WithRequestID(requestID)

	var lastErr error
	for attempt := 0; attempt <= c.config.MaxRetries; attempt++ {
		if attempt > 0 {
			// 重试前等待
			backoffDuration := time.Duration(attempt) * time.Second
			reqLogger.Warn("Retrying Doubao API request", map[string]interface{}{
				"attempt":    attempt,
				"backoff":    backoffDuration.String(),
				"last_error": lastErr.Error(),
			})

			select {
			case <-ctx.Done():
				return "", ctx.Err()
			case <-time.After(backoffDuration):
			}
		}

		result, err := c.doHTTPRequest(ctx, doubaoReq, requestID)
		if err == nil {
			reqLogger.Info("Successfully received response from Doubao API", map[string]interface{}{
				"attempt": attempt,
			})
			return result, nil
		}

		lastErr = err
		reqLogger.Error("Doubao API request failed", map[string]interface{}{
			"attempt": attempt,
			"error":   err.Error(),
		})
	}

	return "", fmt.Errorf("failed to get response after %d attempts: %w", c.config.MaxRetries+1, lastErr)
}

// doHTTPRequest 执行单次HTTP请求到豆包API
func (c *DoubaoClient) doHTTPRequest(ctx context.Context, doubaoReq *model.DoubaoRequest, requestID string) (string, error) {
	reqLogger := c.logger.WithRequestID(requestID)

	// 序列化请求体
	reqBody, err := json.Marshal(doubaoReq)
	if err != nil {
		return "", fmt.Errorf("failed to marshal request: %w", err)
	}

	// 创建HTTP请求
	req, err := http.NewRequestWithContext(ctx, "POST", c.config.APIURL, bytes.NewBuffer(reqBody))
	if err != nil {
		return "", fmt.Errorf("failed to create request: %w", err)
	}

	// 设置请求头
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+c.config.APIKey)

	// 记录请求详情（不包含敏感信息）
	reqLogger.Debug("Sending HTTP request to Doubao API", map[string]interface{}{
		"url":    c.config.APIURL,
		"method": "POST",
	})

	// 发送HTTP请求
	resp, err := c.httpClient.Do(req)
	if err != nil {
		return "", fmt.Errorf("failed to send request: %w", err)
	}
	defer resp.Body.Close()

	// 读取响应体
	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("failed to read response: %w", err)
	}

	reqLogger.Debug("Received HTTP response", map[string]interface{}{
		"status_code": resp.StatusCode,
		"status":      resp.Status,
	})

	// 检查HTTP状态码
	if resp.StatusCode != http.StatusOK {
		reqLogger.Error("Doubao API returned error status", map[string]interface{}{
			"status_code": resp.StatusCode,
			"status":      resp.Status,
			"response":    string(respBody),
		})
		return "", fmt.Errorf("API request failed with status %d: %s", resp.StatusCode, string(respBody))
	}

	// 解析响应
	var doubaoResp model.DoubaoResponse
	if err := json.Unmarshal(respBody, &doubaoResp); err != nil {
		reqLogger.Error("Failed to parse Doubao API response", map[string]interface{}{
			"error":    err.Error(),
			"response": string(respBody),
		})
		return "", fmt.Errorf("failed to parse response: %w", err)
	}

	// 检查响应是否包含有效内容
	if len(doubaoResp.Choices) == 0 {
		return "", fmt.Errorf("no choices in response")
	}

	content := doubaoResp.Choices[0].Message.Content
	if content == "" {
		return "", fmt.Errorf("empty content in response")
	}

	reqLogger.Debug("Successfully parsed Doubao API response", map[string]interface{}{
		"choices_count":  len(doubaoResp.Choices),
		"content_length": len(content),
	})

	return content, nil
}

// buildComprehensivePrompt 构建综合性分析prompt - 豆包版本
func (c *DoubaoClient) buildComprehensivePrompt(imageURL string) string {
	var rulesDesc strings.Builder
	
	for i, rule := range c.rules {
		if !rule.Activate {
			continue
		}
		rulesDesc.WriteString(fmt.Sprintf("规则%d-%s: ", i+1, rule.RulesName))
		var conditions []string
		for _, cond := range rule.Conditions {
			if cond.Value {
				conditions = append(conditions, cond.Content)
			}
		}
		rulesDesc.WriteString(fmt.Sprintf("检查是否包含[%s]\n", strings.Join(conditions, ", ")))
	}

	prompt := fmt.Sprintf(`请分析这张图片的内容。

分析完图片后，请检查是否违反以下规则：
%s

请用JSON格式回复，包含以下字段：
- description: 图片内容描述
- violated: 是否违规(true/false)  
- violated_rules: 违规的规则名称数组
- details: 每个规则的检查详情

示例格式：
{"description":"图片描述","violated":false,"violated_rules":[],"details":[{"rule_name":"规则名","violated":false,"matched_conditions":[]}]}`, rulesDesc.String())

	return prompt
}

// parseAIResponse 解析AI返回的结构化响应
func (c *DoubaoClient) parseAIResponse(aiResponse string, reqLogger *logger.RequestLogger) (map[string]interface{}, error) {
	// 清理响应，移除可能的markdown标记
	cleanResponse := strings.TrimSpace(aiResponse)
	cleanResponse = strings.TrimPrefix(cleanResponse, "```json")
	cleanResponse = strings.TrimPrefix(cleanResponse, "```")
	cleanResponse = strings.TrimSuffix(cleanResponse, "```")
	cleanResponse = strings.TrimSpace(cleanResponse)

	var result map[string]interface{}
	if err := json.Unmarshal([]byte(cleanResponse), &result); err != nil {
		return nil, fmt.Errorf("failed to parse JSON response: %w", err)
	}

	// 验证必要字段
	if _, ok := result["violated"]; !ok {
		return nil, fmt.Errorf("missing 'violated' field in response")
	}
	if _, ok := result["description"]; !ok {
		return nil, fmt.Errorf("missing 'description' field in response")
	}

	return result, nil
}

// fallbackAnalysis 降级分析方法
func (c *DoubaoClient) fallbackAnalysis(ctx context.Context, imageURL, requestID string) (string, error) {
	reqLogger := c.logger.WithRequestID(requestID)
	
	// 使用简单的描述性prompt
	descPrompt := "请分析这张图片的内容，描述你看到的文字、logo、品牌等信息。"
	doubaoReq := c.buildDoubaoRequest(imageURL, descPrompt)
	
	desc, err := c.sendRequest(ctx, doubaoReq, requestID)
	if err != nil {
		return "", fmt.Errorf("Doubao fallback analysis failed: %w", err)
	}

	// 使用本地字符串匹配进行规则检查
	type RuleResult struct {
		RuleName   string   `json:"rule_name"`
		Violated   bool     `json:"violated"`
		Conditions []string `json:"matched_conditions"`
	}
	
	var violatedRuleNames []string
	var ruleResults []RuleResult
	overallViolated := false

	descLower := strings.ToLower(desc)
	
	for _, rule := range c.rules {
		if !rule.Activate {
			continue
		}
		
		matchedConds := []string{}
		violated := false
		
		for _, cond := range rule.Conditions {
			if !cond.Value {
				continue
			}
			
			condStr := strings.TrimSpace(strings.ReplaceAll(cond.Content, "\n", ""))
			condLower := strings.ToLower(condStr)
			
			if strings.Contains(descLower, condLower) {
				matchedConds = append(matchedConds, cond.Content)
				violated = true
				reqLogger.Debug("Doubao fallback rule matched", map[string]interface{}{
					"rule": rule.RulesName,
					"condition": cond.Content,
				})
			}
		}
		
		if violated {
			overallViolated = true
			violatedRuleNames = append(violatedRuleNames, rule.RulesName)
		}
		
		ruleResults = append(ruleResults, RuleResult{
			RuleName:   rule.RulesName,
			Violated:   violated,
			Conditions: matchedConds,
		})
	}

	result := map[string]interface{}{
		"violated":       overallViolated,
		"violated_rules": violatedRuleNames,
		"details":        ruleResults,
		"description":    desc,
	}
	
	resultJson, err := json.Marshal(result)
	if err != nil {
		return "", fmt.Errorf("failed to marshal Doubao fallback result: %w", err)
	}
	
	reqLogger.Info("Doubao fallback analysis completed", map[string]interface{}{
		"violated": overallViolated,
		"matched_rules": len(violatedRuleNames),
		"description": desc,
	})
	
	return string(resultJson), nil
}

// SetRules 设置规则集合
func (c *DoubaoClient) SetRules(rules []config.Rule) {
	c.rules = rules
}

// 确保 DoubaoClient 实现 ImageModelClientInterface
var _ interfaces.ImageModelClientInterface = (*DoubaoClient)(nil)
